package cn.tedu.charging.order.quartz;

import cn.tedu.charging.order.dao.repository.OrderRepository;
import cn.tedu.charging.order.pojo.po.ChargingBillFailPO;
import cn.tedu.charging.order.pojo.po.ChargingBillSuccessPO;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

import java.util.Date;
import java.util.UUID;

@Slf4j
public class DeviceCheckJob implements Job {

    /**
     * 必须需要一个无参的构造器
     */
    public DeviceCheckJob(){}


    public DeviceCheckJob(String orderNo,Integer gunId) throws SchedulerException {
        log.debug("添加设备自检定时任务:订单号:{},枪id:{}",orderNo,gunId);

        //创建调度器工厂
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        //通过调度器工厂创建调度器
        Scheduler scheduler = schedulerFactory.getScheduler();

        JobDetail jobDetail = JobBuilder.newJob(DeviceCheckJob.class)
                //定义定时任务的名称和组
                .withIdentity("DeviceCheckJob" + UUID.randomUUID(),"device_check_jobs")
                //传入订单号
                .usingJobData("orderNo",orderNo)
                //传入枪id
                .usingJobData("gunId",gunId)
                .build();

        //定义任务触发的时间
        //当前时间 + 1分钟 (模拟设备自检需要1分钟)
        //当前时间
        long now = System.currentTimeMillis();
        // 1分钟
        long deviceCheckTime = 1 * 60 * 1000;
        //任务触发时间  当前时间 + 1分钟  任务会在1分钟以后执行
        Date triggerTime = new Date(now + deviceCheckTime);

        //触发器
        Trigger trigger = TriggerBuilder.newTrigger().startAt(triggerTime).build();

        //调度器scheduler  把 任务 jobDetail 和  触发器 trigger 进行绑定
        //调度器 scheduler 让任务 jobDetail 按照 时间 trigger 来触发
        scheduler.scheduleJob(jobDetail,trigger);

        //启动调用器
        scheduler.start();
    }

    /**
     * 任务执行的逻辑
     * @param context
     * @throws JobExecutionException
     */
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        log.debug("设备自检任务开始执行");
//        获取任务数据
        JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
        String orderNo = jobDataMap.getString("orderNo");
        Integer gunId = jobDataMap.getInt("gunId");

        //DeviceCheckJob 没有在Spring-ioc容器里
        //通过 new的方式创建的 OrderServiceImpl new DeviceCheckJob(orderNo,gunId)
        //想使用容器里的 OrderRepository 可以 applicationContext 获取容器里的对应的对象实例
        OrderRepository orderRepository = SpringContextJobUtils.geBean("orderRepository", OrderRepository.class);

//        判断是否有成功或失败订单》》如都没有》》执行代码

        //通过订单号获取成功订单记录
        ChargingBillSuccessPO chargingBillSuccessPO = orderRepository.getSuccessOrder(orderNo);
        if (chargingBillSuccessPO == null) {
            ChargingBillFailPO chargingBillFailPO = orderRepository.getFailOrder(orderNo);
            if (chargingBillFailPO == null) {
                ChargingBillFailPO newChargingBillFailPO = new ChargingBillFailPO();
                newChargingBillFailPO.setFailDesc("设备自检失败-设备无响应");
                newChargingBillFailPO.setBillId(orderNo);
                log.debug("设备自检失败,保存失败订单记录:{}",newChargingBillFailPO);
                Integer row = orderRepository.saveFailOrder(newChargingBillFailPO);
                log.debug("设备自检失败,保存失败订单记录:{},影响行数:{}",newChargingBillFailPO,row);


                log.debug("通知充电用户,请您更换充电设备,给您带来的不便,请谅解...");
                log.debug("调用 营销系统(优惠券服务),给用户发送优惠券 ,通过feign调用优惠券服务的接口");
                log.debug("修改枪的状态为 故障,通过feign调用设备服务的接口");
                log.debug("通过保障服务,通知维修人员对设备进行检查和维护,入参:设备信息{}," +
                        "也可以入参是订单号,保障服务可以通过订单号反查来查询订单服务通过订单号获取对应设备信息");
                //服务之间通信
                //open-feign
                //创建    保障服务  优惠券服务,
                //创建接口 创建维修单,发送优惠券
                //入参 订单号和设备信息
                //出参 统一结果出参
                //维修单表设计
                //维修单基本信息 (id,创建时间,状态(新创建,修理中,完成))
                //设备信息(站id,桩id,枪id,运营商id,运营商联系电话)
                //保障服务 给 维修人员 发通知 派单/抢单
                //给维修人员记录 绩效 维修记录 表设计
                //订单服务增加 feignClient
                // 通过feignClient 调用接口
                //RabbitMQ
                //1 定义保障服务的 Exchange 和 Queue 通过RoutingKey 进行绑定
                //2 在订单服务 定义Producer 用来给Rabbit发送消息 Exchange
                //3 消息的格式: {orderNo:xxx,设备信息:{}}
                //4 保障服务增加 消费者 @RabbitListener 监听 Queue
                //5 消费消息 生成维修单
                //6 幂等性 保障同一个订单 不能搞出多个 维修单
                //7保障服务 给 维修人员 发通知 派单/抢单
                //8 给维修人员记录 绩效 维修记录 表设计

            }else {
                //有失败订单记录,无需修改失败原因,真实的原因 有响应-无法充电 不能 改为 无响应
                log.debug("有失败订单记录,表示设备有响应,不能充电");
                log.debug("无需处理");
            }
        }else {
            //有成功订单记录
            log.debug("有成功订单记录,表示设备有响应,能充电");
            log.debug("更新设备信息到成功订单表:枪id:{},订单号:{},这里只是为了演示业务流程,不是必须操作",gunId,orderNo);
            Integer row = orderRepository.updateDeviceInfo(orderNo,gunId);
            log.debug("更新设备信息到成功订单表:订单号:{},枪id:{},影响行数:{},这里只是为了演示业务流程,不是必须操作",orderNo,gunId,row);
        }
    }
}
